#ifndef _M_LOGSINK_H__
#define _M_LOGSINK_H__

#include"util.hpp"
#include"format.hpp"

namespace bitlog{
    class LogSink{
        public:
        using ptr=shared_ptr<LogSink>;
        LogSink() {}
        virtual void log(const char* data,size_t len)=0;
    };
    class StdoutSink:public LogSink{
        public:
        StdoutSink() {}
        void log(const char* data,size_t len) override{
            cout.write(data,len);
        }
    };
    class FileSink:public LogSink{
        private:
        string _filename;
        ofstream _ofs;
        public:
        FileSink(const string& filename):_filename(filename){
            util::file::create_dir(util::file::path(_filename));
            _ofs.open(_filename,std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }
        void log(const char* data,size_t len) override{
            _ofs.write(data,len);
            if(_ofs.good()==false){
                cout<<"日志写入文件失败-1"<<endl;
                return;
            }
        }
    };
    class RollSink:public LogSink{
        private:
        string _basename;
        ofstream _ofs;
        size_t _max_size;
        size_t _cur_size;
        size_t _filecount;
        public:
        RollSink(const string& basename,size_t max_size)
        :_basename(basename),_max_size(max_size),_cur_size(0)
        {
            util::file::create_dir(util::file::path(basename));
        }
        void log(const char* data,size_t len) override{
            initLogFile();
            _ofs.write(data,len);
            if(_ofs.good()==false){
                cout<<"日志写入文件失败-2"<<endl;
            }
            _cur_size+=len;
        }
        private:
        void initLogFile(){
            if(_ofs.is_open()==false || _cur_size>_max_size){
                _ofs.close();
                string name=create_filename();
                _ofs.open(name,ios::binary | ios::app);
                assert(_ofs.is_open());
                _cur_size=0;
            }
        }
        string create_filename(){
            time_t t=time(nullptr);
            struct tm lt;
            localtime_r(&t,&lt);
            stringstream ss;
            ss<<_basename;
            ss<<lt.tm_year+1990;
            ss<<lt.tm_mon+1;
            ss<<lt.tm_mday;
            ss<<lt.tm_hour;
            ss<<lt.tm_min;
            ss<<lt.tm_sec;
            ss<<"-"<<++_filecount;
            ss<<".log";
            return ss.str();
        }
    };

    class SinkFactor{
        public:
        template<typename Sinktype,typename ...Args>
        static LogSink::ptr createSink(Args&& ...args){
            return make_shared<Sinktype>(forward<Args>(args)...);
        }
    };
}


#endif